package icu.xuyijie.springbootlearning2.chapter6;

import icu.xuyijie.springbootlearning2.chapter6.handler.LoginFailureHandler;
import icu.xuyijie.springbootlearning2.chapter6.handler.LoginSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 徐一杰
 * @date 2025/03/11 09:57
 * @description security的配置文件
 */
@Configuration
public class SpringSecurityConfig {
    /**
     * 加盐的 MD5 算法
     * @return 加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

//    @Bean
//    public UserDetailsService userDetailsService() {
//        return new MyUserDetailsService();
//    }

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();

        List<GrantedAuthority> authorities = new ArrayList<>();

        // 往队列里加入一条角色，角色的前缀必须是 ROLE_
        authorities.add(new SimpleGrantedAuthority("ROLE_student"));
        // 不加前缀，代表加入的是一条 权限
        authorities.add(new SimpleGrantedAuthority("delete"));

        manager.createUser(
                new User(
                        "xyj",
                        // 因为 security 组件，默认会把存储到数据库里的密码字段加密，所以我们模拟数据的时候，也要加密一下
                        passwordEncoder().encode("123456"),
                        authorities
                )
        );

        return manager;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        // 定义如何查询用户
        httpSecurity.userDetailsService(userDetailsService());

        // 根据 url 规则选择不拦截或拦截某些url
        httpSecurity.authorizeHttpRequests(
                authorize -> authorize
                        // 静态资源可以放行
                        .requestMatchers("/*.html").permitAll()
                        // 允许test2开头的所有资源无需鉴权访问
                        .requestMatchers("/test2/**").hasRole("student")
                        .requestMatchers("/test/**").permitAll()
                        .requestMatchers("/actuator/**").permitAll()
                        // 剩下的所有请求都需要验证
                        .anyRequest().authenticated()
        );

        // 如果不采用前后端分离模式，使用默认配置
        //httpSecurity.formLogin(Customizer.withDefaults());

        // 如果采用前后端分离模式，需要自定义 login 界面
        httpSecurity.formLogin(form -> form
                .loginPage("/login")
                .permitAll()
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(new LoginSuccessHandler())
                .failureHandler(new LoginFailureHandler())
        );

        return httpSecurity.build();
    }

}
